// lab1.cpp : Defines the entry point for the console application.
//

#include "StdAfx.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <gl/glut.h>
#include <gl/gl.h>

#define WINDOW_WIDTH 800 // originally 300x300; now will be 4:3 width:height, and big enough to mess with comfortably
#define WINDOW_HEIGHT 600
#define PI 3.14159265357

// May be better to change from global, but not inspired on how to 
//   effect the size variable otherwise
int size;
int brushid;	// Brush identification, to allow cycling
int angle;
int current_color;

void display ( void )
{
	glClear ( GL_COLOR_BUFFER_BIT );
	glFlush ( );
}

void keyboard ( unsigned char key, int x, int y )
{
	switch ( key )
	{
	// Size changes
	case '=':	// intentionally having this fall through, since the '=' key is the same
	case '+':	//	as the '+' key; easily changed if '=' must be used elsewhere
		if(size < 128)	// restrict size to [1,128]
			size *= 2;
		break;
	case '-':
		if(size > 1)	// restrict size to [1,128]
			size /= 2;
		break;

	// Color changes : BGR
	case '1':	// 001
		//red
		current_color = 1;
		glColor3f ( 1, 0, 0 );
		break;
	case '2':	// 010
		//green
		current_color = 2;
		glColor3f ( 0, 1, 0 );
		break;
	case '3':	// 011
		//yellow
		current_color = 3;
		glColor3f ( 1, 1, 0 );
		break;
	case '4':	// 100
		//blue
		current_color = 4;
		glColor3f ( 0, 0, 1 );
		break;
	case '5':	// 101
		//magenta
		current_color = 5;
		glColor3f ( 1, 0, 1 );
		break;
	case '6':	// 110
		//cyan
		current_color = 6;
		glColor3f ( 0, 1, 1 );
		break;
	case '7':
		//white
		current_color = 7;
		glColor3f ( 1, 1, 1 );
		break;
	case '0':
		//black - effectively an eraser
		current_color = 0;
		glColor3f ( 0, 0, 0 );
		break;


	case 'c':	// clear the screen
		glutPostRedisplay();	// should call display()
		break;

	// Change the identity of the brush
	case 'b':
		if(brushid == 3)	{	// check bounds of b / restore to square
			brushid = 0;
			break;
		}
		if(brushid == 4)
			break;
		brushid++;
		break;

	//Rotate the brush
	case 'r':	
		if(angle >= 350)
			angle = 0;
		else
			angle += 10;
		break;

	// Spray can toggle
	case 'a':
		if( brushid == 3 )
		{
			brushid = 4;
			glEnable (GL_BLEND);
			glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		}
		else if( brushid == 4 )
		{
			brushid = 3;
			glDisable (GL_BLEND);
			glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		}
		break;

	default:
		break;
	}
}

// Provided
void init ( void )
{
    glClearColor (0.0, 0.0, 0.0, 0.0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, WINDOW_WIDTH-1, WINDOW_HEIGHT-1, 0, -1.0, 1.0);
	glMatrixMode(GL_MODELVIEW);
}

void mouseMove ( int x, int y )
{
	switch ( brushid )
	{
	case 0:	// square
		glPushMatrix();
			glTranslatef(x,y,0);		// used to change the frame of reference for easier drawing
			glRotatef(angle, 0, 0, 1);	// rotate around a vector coming out of the screen
			glBegin ( GL_QUADS );
				glVertex2f ( -size, -size );
				glVertex2f ( -size, size );
				glVertex2f ( size, size );
				glVertex2f ( size, -size );
			glEnd ( );
		glPopMatrix();
		glFlush();
		break;

	case 1:	// triangle
		glPushMatrix();
			glTranslatef(x,y,0);
			glRotatef(angle, 0, 0, 1);	
			glBegin ( GL_TRIANGLES );
				glVertex2f ( -size, -size );
				glVertex2f ( size, -size );
				glVertex2f ( 0, size );
			glEnd();
		glPopMatrix();
		glFlush();
		break;

	case 2:	// line
		glPushMatrix();
			glTranslatef(x,y,0);
			glRotatef(angle,0,0,1);
			glBegin ( GL_LINES );
				glVertex2f ( 0, -size);
				glVertex2f ( 0, size);
			glEnd();
		glPopMatrix();
		glFlush();
		break;

	case 3:	// circle
		glPushMatrix();
			glTranslatef(x,y,0);
			glBegin ( GL_TRIANGLE_FAN );
				for(double theta = 0; theta < 2*PI; theta += 0.10)
					glVertex2f ( size * cos(theta), size * sin(theta) );
			glEnd ( );
		glPopMatrix();
		glFlush();
		break;

	// To implement the spray can, the circle is drawn as a series of triangle fans, each
	//  with decreasing alpha
	case 4:
		for(double rad = 0; rad < size; rad += 2)	// for each radius
		{
			double d_size = (double)size;	// double version of size
				// Color changes : BGR
				switch (current_color)
				{
				case 1:	// 001
					//red
					glColor4f ( 1, 0, 0, (d_size-rad)/d_size );	// will vary the alpha from
					break;									// 1 at rad = 0 to 0 at rad = size
				case 2:	// 010
					//green
					glColor4f ( 0, 1, 0, (d_size-rad)/d_size );
					break;
				case 3:	// 011
					//yellow
					glColor4f ( 1, 1, 0, (d_size-rad)/d_size );
					break;
				case 4:	// 100
					//blue
					glColor4f ( 0, 0, 1, (d_size-rad)/d_size );
					break;
				case 5:	// 101
					//magenta
					glColor4f ( 1, 0, 1, (d_size-rad)/d_size );
					break;
				case 6:	// 110
					//cyan
					glColor4f ( 0, 1, 1, (d_size-rad)/d_size );
					break;
				case 7:
					//white
					glColor4f ( 1, 1, 1, (d_size-rad)/d_size );
					break;
				case 0:
					//black - effectively an eraser
					glColor4f ( 0, 0, 0, (d_size-rad)/d_size );
					break;
				default:
					break;
				}

		glPushMatrix();
			glTranslatef(x,y,0);

			// The line strip implementation was attempted, but working with Cartesian-ally 
			//    located pixels resulted in gaps in the drawn shape; the triangle fan solution
			//    was deemed to be more aesthetically pleasing, though the alpha gradient was less
			//    noticable except right at the edges (due to the semi-opaque triangles being
			//    drawn on top of other semi-opaque triangles of the same color)
//			glBegin ( GL_LINE_STRIP );	


			glBegin ( GL_TRIANGLE_FAN );
			
					glVertex2f( 0, 0 );	// If doing line strips, comment out this line
					for(double theta = 0; theta < 2*PI; theta += 0.05)	{
						glVertex2f (rad*cos(theta), rad*sin(theta));
					}
					glVertex2f (rad,0);	// complete the circle
			glEnd ( );
		glPopMatrix();
		glFlush();
		}

	default:
		break;
	}

//	glutPostRedisplay ( );
/*	
	glColor3f ( 1, 1, 1 );	// White
	glBegin ( GL_QUADS );
		glVertex2f ( x - size, y - size );
		glVertex2f ( x - size, y + size );
		glVertex2f ( x + size, y + size );
		glVertex2f ( x + size, y - size );
	glEnd ( );
*/
}

int main ( int argc, char *argv[] )
{
	//Initialize
	size = 8;
	brushid = 0;
	angle = 0;
	current_color = 7;



	glutInit(&argc, argv);
    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA);	// changed to GLUT_RGBA to allow blending
    glutInitWindowSize (WINDOW_WIDTH, WINDOW_HEIGHT); 
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("John Lake - Assignment 1");
    init ();
    glutDisplayFunc(display);
	glutMotionFunc ( mouseMove );
	glutKeyboardFunc ( keyboard );
	glutMainLoop ( );
	return 0;
}